#ifndef EIGHTQUEENSOLVER_H
#define EIGHTQUEENSOLVER_H

/*
 * 八皇后算法类，实现回溯求解功能
 * 普通模式下，棋盘用二维数组表示
*/

#include <qelapsedtimer.h>
#include <QObject>
#include <QRunnable>
#include <QVector>

#include "qmutex.h"
#include "qwaitcondition.h"

#define Board1D int*   // 多线程模式，棋盘用一维数组表示
#define Board2D int**  // 普通模式，棋盘用二维数组表示

class EightQueenSolver : public QObject, public QRunnable {
  Q_OBJECT
 public:
  EightQueenSolver(int n, QMutex* mutex = nullptr,
                   QWaitCondition* wc = nullptr);

  // 递归函数
  void solveNQueens(int* flag, int row, int& n);  // 算法：flag回溯

  enum {
    NOQUEEN = 0,  // 二维数组：无皇后
    QUEEN = 1     // 二维数组：有皇后
  };

  void solve();  // 解题

  int getResNum() { return resNum; }  // 获取解的数目
  double getTime() { return time; }   // 获取记录时间

  // 棋盘大小管理
  int getN() { return m_n; }
  void setN(int n);

  // 状态管理
  enum State {
    FREE,      // 空闲
    RUNNING,   // 计算中
    STOPPED,   // 被停止
    PAUSED,    // 暂停
    UNDEFINED  // 异常
  } m_state;   // 当前状态
  State state() { return m_state; }
  bool isStop() { return m_state == STOPPED; }
  bool isPause() { return m_state == PAUSED; }

  // 棋盘管理
  Board2D getBoard() { return nQueens; }
  // 存储刚刚获取的解（每得到一个解，就赋给这个数组，供画板显示）
  Board2D lastRes;

  bool step;    // 是否单步
  bool resOnly; // 是否只显示可行解

 signals:
  void finish();
  void stopped();
  void oneResult();  // 得到一个解时发出
  void stepped();    // 单步模式下，得到一个解时发出

 private:
  // 判断格点是否能放皇后的低效方法
  // 程序实际上没有执行过这个函数
  bool isValid(int row, int col, int& n);

  int m_n;  // 皇后数量

  Board2D nQueens;  // 二维数组棋盘
  int resNum;       // 解的数目

  // 记录执行时间
  QElapsedTimer mstimer;
  double time;

  // 线程阻塞管理，用于实现暂停功能
  QMutex* m_mutex;
  QWaitCondition* m_wait;

 public:
  void run();  // 供线程池调用，被调用时执行solve函数

 public slots:
  void stopSolve();   // 停止求解
  void pauseSolve();  // 暂停
  void setResOnly(int);    // 设置是否只显示可行解
};

#endif  // EIGHTQUEENSOLVER_H
